﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using BeanboxSoftware.BeanMap;

namespace BeanMapTest
{
  [TestClass]
  public class IndexNotationTest
  {
    class KeyTypeOne
    {
    }

    class KeyTypeTwo
    {
    }

    class ValueType
    {
    }

    [TestMethod]
    public void JaggedAccessTest()
    {
      var map = new Map<KeyTypeOne, KeyTypeTwo, ValueType>();

      var a = new KeyTypeOne();
      var i = new KeyTypeTwo();
      var v = new ValueType();

      var child = map[a];

      Assert.IsFalse(map.ContainsKey(a));
      Assert.IsNotNull(child);

      child[i] = v;

      Assert.IsTrue(map.ContainsKey(a));

      Assert.AreEqual(v, map[a][i]);
      Assert.AreEqual(v, map[a, i]);

      map.Clear();
      Assert.IsFalse(map.ContainsKey(a));
      Assert.IsFalse(map.ContainsKey(a, i));
      map[a][i] = v;
      Assert.AreEqual(v, map[a][i]);
      Assert.AreEqual(v, map[a, i]);
      Assert.AreEqual(v, child[i]);
    }

    [TestMethod]
    public void JaggedConfigTest()
    {
      var map = new Map<KeyTypeOne, KeyTypeTwo, ValueType>();

      var a = new KeyTypeOne();
      var i = new KeyTypeTwo();
      var v = new ValueType();
      var e = new ValueType();

      map.DefaultValue = e;

      var child = map[a];

      Assert.AreEqual(e, map[a][i]);
      Assert.AreEqual(e, map[a, i]);
      Assert.AreEqual(e, child[i]);
      Assert.IsFalse(map.ContainsKey(a, i));
      Assert.IsFalse(child.ContainsKey(i));

      map.DefaultGeneration = (k1, k2) => v;

      Assert.AreEqual(v, map[a][i]);

      Assert.IsTrue(map.ContainsKey(a, i));
      Assert.IsTrue(child.ContainsKey(i));

      map.Clear();
      Assert.IsFalse(map.ContainsKey(a, i));
      Assert.AreEqual(v, map[a, i]);

      Assert.IsTrue(map.ContainsKey(a, i));
      Assert.IsTrue(child.ContainsKey(i));
    }

    [TestMethod]
    public void PassGetterAsDelegateKVTest()
    {
      var map = new Map<int, string>();
      map[1] = "1";
      map[2] = "what?";

      var list = new List<int>();
      list.Add(1);
      list.Add(3);

      var w = list.Where(map.ContainsKey).Select(map.Get).ToList();
      Assert.AreEqual(1, w.Count);
      Assert.AreEqual("1", w.First());
    }

    [TestMethod]
    public void PassGetterAsDelegateKKVTest()
    {
      var map = new Map<int, int, string>();
      map[1, 4] = "1";
      map[2, 5] = "what?";

      var list = new List<Tuple<int, int>>();
      list.Add(Tuple.Create(1, 4));
      list.Add(Tuple.Create(2, 3));

      var w = list.Where(map.ContainsKey).Select(map.Get).ToList();
      Assert.AreEqual(1, w.Count);
      Assert.AreEqual("1", w.First());
    }

    [TestMethod]
    public void PassGetterAsDelegateKKKVTest()
    {
      var map = new Map<int, int, int, string>();
      map[1, 2, 3] = "1";
      map[4, 5, 6] = "what?";

      var list = new List<Tuple<int, int, int>>();
      list.Add(Tuple.Create(1, 2, 3));
      list.Add(Tuple.Create(4, 5, 7));

      var w = list.Where(map.ContainsKey).Select(map.Get).ToList();
      Assert.AreEqual(1, w.Count);
      Assert.AreEqual("1", w.First());
    }

    [TestMethod]
    public void GetChildKKVTest()
    {
      var map = new Map<int, int, string>();
      map[1, 2] = "3";

      var child = map.Get(1);

      Assert.AreEqual("3", child[2]);

      child[4] = "5";
      Assert.AreEqual("5", map[1, 4]);

      child[2] = "changed";
      Assert.AreEqual("changed", map[1, 2]);
      Assert.AreEqual("changed", map.Get(1, 2));
    }

    [TestMethod]
    public void SmartGetChildKKVTest()
    {
      var map = new Map<int, int, string>();
      map.DefaultValue = null;

      Assert.AreEqual(0, map.Count);
      var child = map.Get(1);
      Assert.IsNotNull(child);

      Assert.AreEqual(0, child.Count);

      Assert.IsNull(child.Get(2));
      Assert.AreEqual(0, map.Count);
      Assert.IsNull(map.Get(1, 2));
    }

    [TestMethod]
    public void GetChildKKKVTest()
    {
      var map = new Map<int, int, int, string>();
      var childkk = map.Get(1);
      var childk = map.Get(1, 2);

      var childkFromkk = childkk.Get(3); // map[1, 3]

      Assert.AreEqual(0, childkk.Count);
      Assert.AreEqual(0, childk.Count);

      map.DefaultGeneration = (k1, k2, k3) => k1.ToString() + k2.ToString() + k3.ToString();

      Assert.IsFalse(childk.ContainsKey(3));
      Assert.AreEqual("123", childkk.Get(2, 3));
      Assert.AreEqual("123", map.Get(1, 2, 3));
      Assert.IsTrue(childk.ContainsKey(3));

      Assert.IsFalse(childkFromkk.ContainsKey(5));
      map[1, 3, 5] = "set";
      Assert.AreEqual("set", childkFromkk.Get(5));
    }

    [TestMethod]
    public void GetChildWithTuplesKKKVtest()
    {
      var map = new Map<int, int, int, string>();

      var listt2 = new List<Tuple<int, int>>();
      listt2.Add(Tuple.Create(1, 2));

      var listt3 = new List<Tuple<int, int, int>>();
      listt3.Add(Tuple.Create(1, 2, 3));

      var t2 = listt2.Select(map.Get);
      var t3 = listt3.Select(map.Get);

      Assert.AreEqual(0, listt2.Where(map.ContainsKey).Select(map.Get).Count());

      var childrenk = t2.ToList();
      Assert.AreEqual(1, childrenk.Count);

      BeanboxSoftware.BeanMapTest.TestUtils.AssertExceptionThrown<KeyNotFoundException>(() => t3.ToList()); // will throw key not found

      childrenk.Single()[3] = "4";
      Assert.AreEqual(1, t3.Count());
      Assert.AreEqual("4", t3.ToList().First());

      var listk = new List<int>();
      listk.Add(1);
      listk.Add(-1);

      var listOfChildrenKs = listk.Select((Func<int, IMap<int, int, string>>)map.Get);
      listOfChildrenKs.ElementAt(0)[7, 7] = "177";
      listOfChildrenKs.ElementAt(1)[7, 7] = "-177";

      Assert.AreEqual("177", map[1, 7, 7]);
      Assert.AreEqual("-177", map[-1, 7, 7]);
    }
  }
}

